/*
 * FormaHoyos.cpp
 *
 *  Created on: 23/10/2013
 *      Author: ezequiel
 */

#include "FormaHoyos.h"
#define ALTURA 20
#define CANT_PUNTOS 10
FormaHoyos::FormaHoyos() {
	this->textureNormalId = 0;
	this->textureReflexionId = 0;
	tiempo = 0;
	this->hoyo_vertex_buffer_size =  ALTURA* 2 * CANT_PUNTOS * 3;
	this->hoyo_normal_buffer_size =2 * ALTURA* CANT_PUNTOS * 3;
	this->hoyo_index_buffer_size = 2 * ALTURA* CANT_PUNTOS+ 2* ALTURA * ALTURA;
	this->hoyo_vertex_buffer = new GLfloat[this->hoyo_vertex_buffer_size];
	this->hoyo_texture_buffer = new GLfloat[this->hoyo_vertex_buffer_size * 2 / 3 ];
	this->hoyo_normal_buffer = new GLfloat[this->hoyo_normal_buffer_size];
	this->hoyo_index_buffer = new GLuint[this->hoyo_index_buffer_size];
	this->crearForma();
}

FormaHoyos::~FormaHoyos() {
	delete this->hoyo_index_buffer;
	delete this->hoyo_normal_buffer;
	delete this->hoyo_vertex_buffer;
	delete this->hoyo_texture_buffer;
}

void FormaHoyos::crearForma() {
	glm::vec3 vect;
		CurvaBessier* curvaS;
		std::vector<glm::vec3> curvaA;
		std::vector<glm::vec3> curvaB;
		std::vector <glm::vec3> curvaZ;
		//////// curva de forma A  ///////


		vect = glm::vec3(0.0f, 0.0f , 0.0f);
		curvaA.push_back(vect);
		vect = glm::vec3(5.0f, 9.0f , 0.0f);
		curvaA.push_back(vect);
		vect = glm::vec3(10.0f, 13.0f, 0.0f);
		curvaA.push_back(vect);
		vect = glm::vec3(15.0f, 0.0f , 0.0f);
		curvaA.push_back(vect);
		curvaS = new CurvaBessier(curvaA, CANT_PUNTOS - 1);
		curvaA = curvaS->obtenerPuntos();


		//////// curva de forma B  ///////
		vect = glm::vec3(15.0f, 0.0f , 0.0f);
		curvaB.push_back(vect);
		vect = glm::vec3(10.0f, -9.0f , 0.0f);
		curvaB.push_back(vect);
		vect = glm::vec3(5.0f, -13.0f, 0.0f);
		curvaB.push_back(vect);
		vect = glm::vec3(0.0f, 0.0f , 0.0f);
		curvaB.push_back(vect);
		curvaS = new CurvaBessier(curvaB, CANT_PUNTOS - 1);
		curvaB = curvaS->obtenerPuntos();
		delete curvaS;
		/////////// curva en z /////////////


		vect = glm::vec3(0.0f, 0.0f , 0.0f);
		curvaZ.push_back(vect);
		vect = glm::vec3(0.0f, 0.0f , 3.0f);
		curvaZ.push_back(vect);
		vect = glm::vec3(0.0f, 0.0f, 5.0f);
		curvaZ.push_back(vect);
		vect = glm::vec3(0.0f, 0.0f , 7.0f);
		curvaZ.push_back(vect);
		curvaS = new CurvaBessier(curvaZ, ALTURA - 1);
		curvaZ = curvaS->obtenerPuntos();
		delete curvaS;
		//////////////// curva de anchos //////////////


    	std::vector<glm::vec3> vecGrosor;
    	vect = glm::vec3(5.0f, 1.0f , 0.0f);
    	vecGrosor.push_back(vect);
    	vect = glm::vec3(10.0f, 1.0f , 0.0f);
    	vecGrosor.push_back(vect);
    	vect = glm::vec3(15.0f, 1.0f , 0.0f);
    	vecGrosor.push_back(vect);
    	vect = glm::vec3(20.0f, -0.03f , 0.0f);
    	vecGrosor.push_back(vect);
    	CurvaBessier* curvaGrosor = new CurvaBessier(vecGrosor, ALTURA - 1 );
    	vecGrosor = curvaGrosor->obtenerPuntos();
    	delete curvaGrosor;

    	std::vector<glm::vec3> vecGrosorAux;
    	vect = glm::vec3(5.0f, 0.0f , 0.0f);
    	vecGrosorAux.push_back(vect);
    	vect = glm::vec3(10.0f, 0.0f , 0.0f);
    	vecGrosorAux.push_back(vect);
    	vect = glm::vec3(15.0f, 0.0f , 0.0f);
    	vecGrosorAux.push_back(vect);
    	vect = glm::vec3(20.0f, 1.0f , 0.0f);
    	vecGrosorAux.push_back(vect);
    	CurvaBessier* curvaGrosorAux = new CurvaBessier(vecGrosorAux, ALTURA - 1 );
    	vecGrosorAux = curvaGrosorAux->obtenerPuntos();
    	delete curvaGrosorAux;

		/////////// variables //////////7
    	 float pasoU = 0;
    		    float pasoV = 0.0;

		int i,j,p,k,z;
    		    p = 0 ;
		z = 0 ;
		k = 0;
		for (z = 0; z < ALTURA - 1 ; z++){
		j= 0;
		pasoU = 0.0;
//		pasoV = 0.0;
	    pasoV = pasoV + 0.05;
				    	for( i = 6 * CANT_PUNTOS * z  ;i <  3  * CANT_PUNTOS + 6 * CANT_PUNTOS * z; i = i + 3)
				    		    	{
				    		    		this->hoyo_vertex_buffer[i] = (curvaA[j].x + curvaZ[z].x) * vecGrosor[z].y + 7.5f * vecGrosorAux[z].y ;
				    		    		this->hoyo_vertex_buffer[i+1] = ( curvaA[j].y + curvaZ[z].y  ) *  vecGrosor[z].y  ;
				    		    		this->hoyo_vertex_buffer[i+2] = (curvaA[j].z  + curvaZ[z].z )  ;
				    		    		this->hoyo_texture_buffer[p] = pasoU;
				    		    		p++;
				    		    		 this->hoyo_texture_buffer[p] = pasoV;
				    		    		p++;
				    		    		pasoU = pasoU + 0.05 ;
//				    		    		this->hoyo_normal_buffer[i] = 0.15f;
//				    		    		this->hoyo_normal_buffer[i+1] = 0.15f;
//				    		    		this->hoyo_normal_buffer[i+2] = 0.15f;
//				    		    			    		this->hoyo_index_buffer[i] = j + 2 * z * CANT_PUNTOS;
//				    		    			    		this->hoyo_index_buffer[i+1] = j + 2 * z * CANT_PUNTOS;
//				    		    			    		this->hoyo_index_buffer[i+2] = j + 2 *  z * CANT_PUNTOS;
				    		    			    		j++;
				    		    	}
		//	}


				    	 k = j;
				    	 j= 0;
//				    	 pasoU = 0;
		//		for (int z = 0 ; z < ALTURA ; z++  ){
				    		    	for( i = 3 * CANT_PUNTOS +  6 * CANT_PUNTOS * z ;i < 6 * CANT_PUNTOS + z * CANT_PUNTOS * 6; i = i + 3)
				    		    		    {
				    		    		    	this->hoyo_vertex_buffer[i] = (curvaB[j].x + curvaZ[z].x) * vecGrosor[z].y + 7.5f * vecGrosorAux[z].y  ;
				    		    		    	this->hoyo_vertex_buffer[i+1] = ( curvaB[j].y  + curvaZ[z].y )* vecGrosor[z].y  ;
				    		    		    	this->hoyo_vertex_buffer[i+2] = (curvaB[j].z  + curvaZ[z].z )  ;
						    		    		this->hoyo_texture_buffer[p] = pasoU;
						    		    		p++;
						    		    		this->hoyo_texture_buffer[p] = pasoV;
						    		    		p++;
						    		    		pasoU = pasoU + 0.05 ;
//				    		    		    	this->hoyo_normal_buffer[i] = 0.15f;
//				    		    		    	this->hoyo_normal_buffer[i+1] = 0.15f;
//				    		    		    	this->hoyo_normal_buffer[i+2] = 0.15f;
//				    		    		    	this->hoyo_index_buffer[i] = k + 2 *z *CANT_PUNTOS;
//				    		    		    	this->hoyo_index_buffer[i+1] = k + 2 *z * CANT_PUNTOS ;
//				    		    		    	this->hoyo_index_buffer[i+2] = k + 2 * z * CANT_PUNTOS;
				    		    		    			    		j++;
				    		    		    			    		k++;
				    		    		    	}
		}

		this->indexar();
//		this->calcularNormales();
}

void FormaHoyos::render(GLuint handle, glm::mat4* matModelo) {

//
//	    glUseProgram(handle );
//
//	    // Bind View Matrix
//	    this->cam->bindViewCamara(handle);
//
//	    // Bind Projection MAtrix
//	    GLuint location_projection_matrix = glGetUniformLocation( handle, "ProjectionMatrix");
//	    if( location_projection_matrix >= 0 )
//		{
//			glUniformMatrix4fv( location_projection_matrix, 1, GL_FALSE, &this->proyeccion[0][0]);
//		}
//	    //
//	    ///////////////////////////////////////////
//
//
//
//	    //////////////////////////////////////
//	    // Bind Light Settings
//	    glm::vec4 light_position = glm::vec4( 180.0f, 180.0f, 180.0f, 1.0f );
//	    glm::vec3 light_intensity = glm::vec3( 1.0f, 1.0f, 1.0f );
//
//	    GLuint location_light_position = glGetUniformLocation( handle, "LightPosition");
//	    if( location_light_position >= 0 )
//		{
//	        glUniform4fv( location_light_position, 1, &light_position[0]);
//		}
//
//	    GLuint location_light_intensity = glGetUniformLocation( handle, "Ld");
//	    if( location_light_intensity >= 0 )
//		{
//			glUniform3fv( location_light_intensity, 1, &light_intensity[0]);
//		}
	this->renderMatrix(handle, &proyeccion);


	// Normal Matrix
	glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(*matModelo)));



		// Bind Light Settings
				// ###################
	glm::vec3 light_intensity = glm::vec3(0.4f, 0.2f, 0.2f);
//	glm::vec4 light_position = glm::vec4(0.0f, 1.0f, 0.0f, 0.0f);
	 glm::vec4 light_position = glm::vec4( 0.0f, 1.0f, 0.0f, 0.0f );
//			    glm::vec3 light_intensity = glm::vec3( 1.0f, 1.0f, 1.0f );
	glm::vec3 La = glm::vec3(0.5f, 0.2f, 0.1f);
	glm::vec3 Ld = glm::vec3(1.0f, 1.0f, 1.0f);
	glm::vec3 Ls = glm::vec3(0.1f, 1.0f, 0.6f);
	glm::vec3 Ka = glm::vec3(0.2f, 0.2f, 0.2f);;
	glm::vec3 Kd = glm::vec3(0.8f, 0.8f, 0.8f);
	glm::vec3 Ks = glm::vec3(0.25f, 0.0f, 0.0f);
	float Shininess = 0.5;

				// Light Intensity
				GLuint location_light_intensity = glGetUniformLocation(handle,
					"LightIntensity");

				if(location_light_intensity >= 0)
					glUniform3fv( location_light_intensity, 1, &light_intensity[0]);
				else
					cout << "PROBLEM " << endl;
				// Light Position
				GLuint location_light_position = glGetUniformLocation(handle,
					"LightPosition");

				if(location_light_position >= 0)
					glUniform4fv( location_light_position, 1, &light_position[0]);

				// La
				GLuint location_la = glGetUniformLocation(
					handle, "La");

				if(location_la >= 0)
					glUniform3fv( location_la, 1, &La[0]);

				// Ld
				GLuint location_ld = glGetUniformLocation(
					handle, "Ld");

				if(location_ld >= 0)
					glUniform3fv( location_ld, 1, &Ld[0]);

				// Ls
				GLuint location_ls = glGetUniformLocation(
					handle, "Ls");

				if(location_ls >= 0)
					glUniform3fv( location_ls, 1, &Ls[0]);


				// Ka
				GLuint location_ka = glGetUniformLocation(
					handle, "Ka");

				if(location_ka >= 0)
					glUniform3fv( location_ka, 1, &Ka[0]);

				// Kd
				GLuint location_kd = glGetUniformLocation(
					handle, "Kd");

				if(location_kd >= 0)
					glUniform3fv( location_kd, 1, &Kd[0]);

				// Ks
				GLuint location_ks = glGetUniformLocation(
					handle, "Ks");

				if(location_ks >= 0)
					glUniform3fv( location_ks, 1, &Ks[0]);


				// Shininess
				GLfloat location_shininess = glGetUniformLocation(handle,
					"Shininess");

				if(location_shininess >= 0)
					glUniform1f(location_shininess, Shininess);

//    glm::mat3 normal_matrix = glm::mat3 ( 1.0f );
 // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation(handle, "NormalMatrix");
    if( location_normal_matrix >= 0 )
	{
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]);
	}

    // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( handle, "ModelMatrix");
    if( location_model_matrix >= 0 )
	{
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE,&((*matModelo)[0][0]));
	}
//    glBindTexture (GL_TEXTURE_2D, this->textureid);
//    int loc = glGetUniformLocation(handle, "Tex1");
//    				    if( loc >= 0 )
//    				    {
//    						// We indicate that Uniform Variable sampler2D "text" uses  Texture Unit 0
//    				        glUniform1i(loc, 0);
//    				    }
//    				    else
//    				    {
//    				        fprintf(stderr, "Uniform variable Tex1 not found!\n");
//    				    }

    float lightRadius = 2.0f;
	GLuint radioLuz = glGetUniformLocation(handle, "lightRadius");
				    if( radioLuz >= 0 )
					{
				    	glUniform1f( radioLuz, lightRadius);
					}
    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    int loc = glGetUniformLocation(handle, "Tex1");
    glUniform1i(loc, 0);
    glBindTexture(GL_TEXTURE_2D, this->textureid);

    if(this->textureNormalId != 0){
    glActiveTexture(GL_TEXTURE1);
    glEnable(GL_TEXTURE_2D);
    int loc1 = glGetUniformLocation(handle, "NormalMapTex");
    glUniform1i(loc1, 1);
    glBindTexture(GL_TEXTURE_2D, this->textureNormalId);  }

    if(this->textureReflexionId != 0){
    	glActiveTexture (GL_TEXTURE2);
    int loc2 = glGetUniformLocation(handle, "ReflexionMap");
    glUniform1i(loc2, 2);
//    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
//    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
//    glEnable(GL_TEXTURE_GEN_S);
//    glEnable(GL_TEXTURE_GEN_T);
    	glBindTexture (GL_TEXTURE_2D, this->textureReflexionId); }

    glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glVertexPointer(3, GL_FLOAT, 0,hoyo_vertex_buffer);
	glNormalPointer(GL_FLOAT, 0, hoyo_vertex_buffer);
	glTexCoordPointer(2, GL_FLOAT, 0, hoyo_texture_buffer);
    glDrawElements(GL_TRIANGLE_STRIP, this->hoyo_index_buffer_size, GL_UNSIGNED_INT, this->hoyo_index_buffer);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
}

void FormaHoyos::indexar() {
	int malla[20][20];

		        int e = 0;
		        for(int m = 0; m < 20; m++)
		                for(int n = 0; n < 20; n++)
		                        malla[m][n] = e++;


		        int sentido = 1;
		        int k = 0;

		        for(int i=0; i < (19); i++)
		        {
		                if(sentido == 1)
		                {
		                        for(int j=0; j <= (19); j++) {
		                                this->hoyo_index_buffer[k++] = malla[i][j];
		                                this->hoyo_index_buffer[k++] = malla[i+1][j];
		                        }

		                        sentido = -1;
		                }
		                else if(sentido == -1)
		                {
		                        for(int j=(19); j >= 0; j--) {
		                                this->hoyo_index_buffer[k++] = malla[i][j];
		                                this->hoyo_index_buffer[k++] = malla[i+1][j];
		                        }

		                        sentido = 1;
		                }
		        }

}

void FormaHoyos::calcularNormales() {

	glm::vec3 vecResult;
		glm::vec3 vec1;
		glm::vec3 vec2;

	for (int k = 0 ; k < ALTURA - 1 ; k++){
		for (int i = k * CANT_PUNTOS * 3 ; i < k * CANT_PUNTOS * 3 + CANT_PUNTOS * 3 ; i = i +3 )
		{
			vec1.x = hoyo_vertex_buffer[i] - hoyo_vertex_buffer[i+6*CANT_PUNTOS];
			vec1.y = hoyo_vertex_buffer[i+1] - hoyo_vertex_buffer[i+6*CANT_PUNTOS+1];
			vec1.z = hoyo_vertex_buffer[i+2] - hoyo_vertex_buffer[i+6*CANT_PUNTOS+2];
			vec2.x = hoyo_vertex_buffer[i] - hoyo_vertex_buffer[i+3];
			vec2.y = hoyo_vertex_buffer[i+1] -hoyo_vertex_buffer[i+4];
			vec2.z = hoyo_vertex_buffer[i+2] -hoyo_vertex_buffer[i+5];
			vecResult = calcularNormal(vec1, vec2);
			hoyo_normal_buffer[i] = vecResult.x;
			hoyo_normal_buffer[i+1] = vecResult.y;
			hoyo_normal_buffer[i+2] = vecResult.z;

		}
	}
}

void FormaHoyos::render(GLuint unsignedInt) {
}

glm::vec3 FormaHoyos::calcularNormal(glm::vec3 vec1, glm::vec3 vec2) {
	glm::vec3 retorno;
	retorno.x = vec1.y * vec2.z - vec1.z * vec2.y;
		retorno.y = vec1.z * vec2.x - vec1.x * vec2.z;
		retorno.z =vec1.x * vec2.y - vec1.y * vec2.x;
	return retorno;
}
